package org.create.builder;

import org.create.bean.FieldInfo;
import org.create.bean.TableInfo;
import org.create.utils.DataTool;
import org.create.utils.JsonUtils;
import org.create.utils.LogTool;
import org.create.utils.ReadProperties;

import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;

import static org.create.bean.Constants.*;


public class BuildTable {
    private static Connection conn = null;
    private static boolean haveDate = false;
    private static boolean haveDateTime = false;
    private static boolean haveBigDecimal = false;


    static {
        String driverClassName = ReadProperties.getValue("jdbc.driverClassName");
        String url = ReadProperties.getValue("jdbc.url");
        String username = ReadProperties.getValue("jdbc.username");
        String password = ReadProperties.getValue("jdbc.password");
        try {
            Class.forName(driverClassName);
            conn = DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            LogTool.printMsg("未找到驱动类");
        } catch (SQLException e) {
            LogTool.printError(e);
        }
    }

    private static List<TableInfo> getTableList() {
        List<TableInfo> tableList = new ArrayList<>();
        try {
            PreparedStatement ps = conn.prepareStatement(SHOW_TABLE_SQL);
            ResultSet tableSet = ps.executeQuery();
            while (tableSet.next()) {
                TableInfo tableInfo = new TableInfo();
                String tableName = tableSet.getString("Name");
                String beanName = DataTool.strToHump(tableName, PREFIX, SUFFIX);
                String beanParamName = beanName + SUFFIX_PARAM;
                String comment = tableSet.getString("Comment");
                List<FieldInfo> fieldList = getFields(tableName);

                tableInfo.setTableName(tableName);
                tableInfo.setBeanName(beanName);
                tableInfo.setBeanParamName(beanParamName);
                tableInfo.setComment(comment);
                tableInfo.setFieldList(fieldList);
                tableInfo.setHaveDate(haveDate);
                tableInfo.setHaveDateTime(haveDateTime);
                tableInfo.setHaveBigDecimal(haveBigDecimal);
                setKeyIndexInfo(tableInfo);

                tableList.add(tableInfo);
            }
        } catch (SQLException e) {
            LogTool.printError(e);
        } finally {
            closeConn(conn);
        }
        return tableList;
    }

    private static void setKeyIndexInfo(TableInfo tableInfo) {
        try {
            PreparedStatement ps = conn.prepareStatement(SHOW_TABLE_INDEX.replace("@", tableInfo.getTableName()));
            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                int konUnique = rs.getInt("Non_unique");
                if (konUnique == 1) {
                    continue;
                }
                String keyName = rs.getString("Key_name");
                String columnName = rs.getString("Column_name");
                List<FieldInfo> fieldInfoList = tableInfo.getFieldList()
                        .stream()
                        .filter((e) -> e.getFieldName().equals(columnName))
                        .collect(Collectors.toList());
                if (tableInfo.getKeyIndexMap().containsKey(keyName)) {
                    tableInfo.getKeyIndexMap().get(keyName).addAll(fieldInfoList);
                } else {
                    tableInfo.getKeyIndexMap().put(keyName, fieldInfoList);
                }
            }
        } catch (SQLException e) {
            LogTool.printError(e);
        }
    }

    private static List<FieldInfo> getFields(String tableName) {
        List<FieldInfo> fieldList = new ArrayList<>();
        try {
            PreparedStatement ps = conn.prepareStatement(SHOW_FULL_FIELDS_SQL.replace("@", tableName));
            ResultSet fields = ps.executeQuery();
            Map<String, String> resultMap = new HashMap<>();
            resultMap.put("dateTime", "");
            resultMap.put("date", "");
            resultMap.put("bigDecimal", "");
            while (fields.next()) {
                FieldInfo fieldInfo = new FieldInfo();
                String fieldName = fields.getString("Field");
                String propertyName = DataTool.strToHump(fieldName, PREFIX, SUFFIX, false);
                String sqlType = fields.getString("Type");
                DataTool.sqlTypeToJavaType(sqlType.contains("(") ? sqlType.split("\\(")[0] : sqlType, resultMap);
                String javaType = resultMap.get("javaType");
                String comment = fields.getString("Comment");
                boolean isAutoIncrement = fields.getString("Extra").equals("auto_increment");

                fieldInfo.setFieldName(fieldName);
                fieldInfo.setPropertyName(propertyName);
                fieldInfo.setSqlType(sqlType);
                fieldInfo.setJavaType(javaType);
                fieldInfo.setComment(comment);
                fieldInfo.setIsAutoIncrement(isAutoIncrement);

                fieldList.add(fieldInfo);
            }
            haveDate = resultMap.get("date").equals("true");
            haveDateTime = resultMap.get("dateTime").equals("true");
            haveBigDecimal = resultMap.get("bigDecimal").equals("true");

        } catch (SQLException e) {
            LogTool.printError(e);
        }
        return fieldList;
    }

    public static void closeConn(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                LogTool.printError(e);
            }
        }
    }

    public static List<TableInfo> run() {
        List<TableInfo> tableInfoList = getTableList();
        DataTool.saveJsonToFile(JsonUtils.toJson(tableInfoList), SAVE_TABLE_INFO_PATH);
        return tableInfoList;
    }
}
